home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sprite 1984 - 1993
/
Sprite 1984 - 1993.iso
/
src
/
machserver
/
1.098
/
proc
/
procMisc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-04-29
|
45KB
|
1,638 lines
/*
* procMisc.c --
*
* Misc. routines to get and set process state.
*
* Copyright 1986 Regents of the University of California
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies. The University of California
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*/
#ifndef lint
static char rcsid[] = "$Header: /sprite/src/kernel/proc/RCS/procMisc.c,v 9.16 91/04/29 16:31:46 kupfer Exp $ SPRITE (Berkeley)";
#endif /* not lint */
#include <sprite.h>
#include <proc.h>
#include <status.h>
#include <sync.h>
#include <sched.h>
#include <sig.h>
#include <stdlib.h>
#include <list.h>
#include <string.h>
#include <procInt.h>
#include <rpc.h>
#include <dbg.h>
#include <vm.h>
#include <ctype.h>
#include <fscache.h>
#include <fsutil.h>
#include <rpcClient.h>
#include <rpcServer.h>
#include <procServer.h>
#include <fsrmt.h>
#include <bstring.h>
#include <stdio.h>
#define min(a,b) ((a) < (b) ? (a) : (b))
/*
* Procedures internal to this file
*/
static ReturnStatus GetRemotePCB _ARGS_((int hostID, Proc_PID pid,
Proc_PCBInfo *pcbPtr, char *argString));
static void FillPCBInfo _ARGS_((Proc_ControlBlock *pcbPtr,
Proc_PCBInfo *statusInfoPtr));
/*
*----------------------------------------------------------------------
*
* Proc_Init --
*
* Called during startup to initialize data structures.
*
* Results:
* None.
*
* Side effects:
* Process table initialized, debug list initialized, locks initialized.
*
*----------------------------------------------------------------------
*/
void
Proc_Init()
{
ProcInitTable();
ProcDebugInit();
}
/*
*----------------------------------------------------------------------
*
* Proc_GetPCBInfo --
*
* Returns the process control blocks for the specified processes
* on the specified host. If firstPid is equal to PROC_MY_PID
* and the hostID is PROC_MY_HOSTID, then the PCB for the current
* process is returned. Otherwise PCBs for all processes in the
* range firstPid to lastPid on host hostID are returned. Only
* the index portions of the processIDs for firstPid and lastPid
* are relevant.
*
* Results:
* SYS_INVALID_ARG - firstPid was < 0, firstPid > lastPid
* SYS_ARG_NOACCESS - The buffers to store the pcbs in were not
* accessible.
* *trueNumBuffers is set to be the actual number of
* PCBs returned which can be less than the number requested if
* lastPid - firstPid is greater than the maximum PCBs available.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
/*
* Macro to fix up ticks for a process control block.
*/
#define TICKS_TO_TIME(pcbEntry) \
Timer_TicksToTime(pcbEntry.kernelCpuUsage.ticks, \
&pcbEntry.kernelCpuUsage.time); \
Timer_TicksToTime(pcbEntry.userCpuUsage.ticks, \
&pcbEntry.userCpuUsage.time); \
Timer_TicksToTime(pcbEntry.childKernelCpuUsage.ticks, \
&pcbEntry.childKernelCpuUsage.time); \
Timer_TicksToTime(pcbEntry.childUserCpuUsage.ticks, \
&pcbEntry.childUserCpuUsage.time);
ReturnStatus
Proc_GetPCBInfo(firstPid, lastPid, hostID, infoSize, bufferPtr,
argsPtr, trueNumBuffersPtr)
Proc_PID firstPid; /* First pid to get info for. */
Proc_PID lastPid; /* Last pid to get info for. */
int hostID; /* Host ID to get info for. */
int infoSize; /* Size of structure */
Address bufferPtr; /* Pointer to buffers. */
Proc_PCBArgString *argsPtr; /* Pointer to argument strings. */
int *trueNumBuffersPtr; /* The actual number of buffers
used.*/
{
register Proc_ControlBlock *procPtr = (Proc_ControlBlock *) NIL;
int i, j;
char argString[PROC_PCB_ARG_LENGTH];
Proc_ControlBlock pcbEntry;
Boolean remote = FALSE;
Proc_PID processID = firstPid;
ReturnStatus status = SUCCESS;
Proc_PCBInfo statusInfo;
int bytesToCopy;
if (firstPid != PROC_MY_PID) {
firstPid &= PROC_INDEX_MASK;
lastPid &= PROC_INDEX_MASK;
if ((firstPid > lastPid) ||
((firstPid == PROC_MY_PID) && hostID != PROC_MY_HOSTID)) {
return(GEN_INVALID_ARG);
}
}
if (bufferPtr == USER_NIL) {
return (SYS_ARG_NOACCESS);
}
if (hostID != PROC_MY_HOSTID &&
(hostID <= 0 || hostID > NET_NUM_SPRITE_HOSTS)) {
return(GEN_INVALID_ARG);
}
bytesToCopy = min(sizeof(Proc_PCBInfo), infoSize);
/*
* Determine whether to get process table entries for this machine.
* Currently, the information for this machine is returned unless
* another machine is explicitly specified; i.e., migrated processes
* get information for their current machine rather than their home.
*/
if (hostID == PROC_MY_HOSTID) {
#ifdef FORWARD_MIGRATED_GET_PCBS
procPtr = Proc_GetCurrentProc();
Proc_Lock(procPtr);
if (procPtr->genFlags & PROC_FOREIGN) {
hostID = procPtr->peerHostID;
processID = procPtr->peerHostID;
remote = TRUE;
}
Proc_Unlock(procPtr);
#endif /* FORWARD_MIGRATED_GET_PCBS */
} else if (hostID != rpc_SpriteID) {
remote = TRUE;
}
if (firstPid == PROC_MY_PID) {
/*
* Return PCB for the current process.
*/
procPtr = Proc_GetCurrentProc();
if (!remote) {
bcopy((Address)procPtr, (Address)&pcbEntry,
sizeof (Proc_ControlBlock));
TICKS_TO_TIME(pcbEntry);
FillPCBInfo(&pcbEntry, &statusInfo);
} else {
status = GetRemotePCB(hostID, processID, &statusInfo,
argString);
if (status != SUCCESS) {
return(status);
}
}
if (Proc_ByteCopy(FALSE, bytesToCopy,
(Address)&statusInfo, (Address) bufferPtr) != SUCCESS) {
return(SYS_ARG_NOACCESS);
}
if (argsPtr != (Proc_PCBArgString *) USER_NIL) {
if (!remote) {
if (procPtr->argString != (Address) NIL) {
(void) strncpy(argString, procPtr->argString,
PROC_PCB_ARG_LENGTH - 1);
argString[PROC_PCB_ARG_LENGTH - 1] = '\0';
} else {
argString[0] = '\0';
}
}
if (Proc_ByteCopy(FALSE, PROC_PCB_ARG_LENGTH, argString,
(Address) argsPtr) != SUCCESS) {
return(SYS_ARG_NOACCESS);
}
}
} else {
/*
* Return PCB for all processes or enough to fill all of
* the buffers, whichever comes first.
*/
for (i = firstPid, j = 0;
i <= lastPid;
i++, j++, (Address) bufferPtr += infoSize) {
if (!remote) {
if (i >= proc_MaxNumProcesses) {
break;
}
procPtr = Proc_GetPCB(i);
if (procPtr == (Proc_ControlBlock *) NIL) {
panic("Proc_GetInfo: procPtr == NIL!\n");
status = FAILURE;
break;
}
bcopy((Address)procPtr, (Address)&pcbEntry,
sizeof (Proc_ControlBlock));
TICKS_TO_TIME(pcbEntry);
FillPCBInfo(&pcbEntry, &statusInfo);
} else {
status = GetRemotePCB(hostID, (Proc_PID) i, &statusInfo,
argString);
if (status != SUCCESS) {
/*
* Break if we hit an error. The typical error condition
* is to hit an invalid process ID, which happens since
* we don't know proc_MaxNumProcesses on the other
* machine. Instead, we convert GEN_INVALID_ARG to
* SUCCESS and return what we found so far.
*/
if (status == GEN_INVALID_ARG) {
status = SUCCESS;
}
break;
}
}
if (Proc_ByteCopy(FALSE, bytesToCopy,
(Address)&statusInfo, (Address) bufferPtr) != SUCCESS) {
return(SYS_ARG_NOACCESS);
}
if (argsPtr != (Proc_PCBArgString *) USER_NIL) {
if (!remote) {
if (procPtr->argString != (Address) NIL) {
(void) strncpy(argString, procPtr->argString,
PROC_PCB_ARG_LENGTH - 1);
argString[PROC_PCB_ARG_LENGTH - 1] = '\0';
} else {
argString[0] = '\0';
}
}
if (Proc_ByteCopy(FALSE, PROC_PCB_ARG_LENGTH, argString,
(Address) &(argsPtr[j])) != SUCCESS) {
return(SYS_ARG_NOACCESS);
}
}
}
if (trueNumBuffersPtr != USER_NIL) {
if (Proc_ByteCopy(FALSE, sizeof(j), (Address) &j,
(Address) trueNumBuffersPtr) != SUCCESS) {
return(SYS_ARG_NOACCESS);
}
}
}
return(status);
}
/*
* Define some constants used to distinguish RPC sub-commands.
*/
#define GET_PCB 1
#define GET_SEG_INFO 2
/*
*----------------------------------------------------------------------
*
* GetRemotePCB --
*
* Perform an RPC to get a process control block from another host.
*
* Results:
* The return status from the RPC is returned.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static ReturnStatus
GetRemotePCB(hostID, pid, pcbPtr, argString)
int hostID; /* Host to send RPC to. */
Proc_PID pid; /* index of PCB to obtain. */
Proc_PCBInfo *pcbPtr; /* Place to return PCB data. */
char *argString; /* Place to return argument string. */
{
Rpc_Storage storage;
ReturnStatus status;
int request;
request = GET_PCB;
storage.requestParamPtr = (Address)&request;
storage.requestParamSize = sizeof(request);
storage.requestDataPtr = (Address)&pid;
storage.requestDataSize = sizeof(Proc_PID);
storage.replyParamPtr = (Address)pcbPtr;
storage.replyParamSize = sizeof(Proc_PCBInfo);
storage.replyDataPtr = (Address)argString;
storage.replyDataSize = PROC_PCB_ARG_LENGTH;
status = Rpc_Call(hostID, RPC_PROC_GETPCB, &storage);
if (status == SUCCESS && storage.replyDataSize == 0) {
argString[0] = '\0';
}
return(status);
}
/*
*----------------------------------------------------------------------
*
* Proc_GetRemoteSegInfo --
*
* Perform an RPC to get info for a VM segment control from another host.
*
* Results:
* The return status from the RPC is returned.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
ReturnStatus
Proc_GetRemoteSegInfo(hostID, segNum, segInfoPtr)
int hostID; /* Host to send RPC to. */
int segNum; /* index of segment to obtain. */
Vm_SegmentInfo *segInfoPtr; /* Place to return segment data. */
{
Rpc_Storage storage;
ReturnStatus status;
int request;
request = GET_SEG_INFO;
storage.requestParamPtr = (Address)&request;
storage.requestParamSize = sizeof(request);
storage.requestDataPtr = (Address)&segNum;
storage.requestDataSize = sizeof(int);
storage.replyParamPtr = (Address)segInfoPtr;
storage.replyParamSize = sizeof(Vm_SegmentInfo);
storage.replyDataPtr = (Address)NIL;
storage.replyDataSize = 0;
status = Rpc_Call(hostID, RPC_PROC_GETPCB, &storage);
return(status);
}
/*
*----------------------------------------------------------------------
*
* FillPCBInfo --
*
* Fills in a Proc_PCBInfo structure from the contents of a
* control block.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static void
FillPCBInfo(pcbPtr, statusInfoPtr)
Proc_ControlBlock *pcbPtr; /* Ptr to pcb to convert */
Proc_PCBInfo *statusInfoPtr; /* Structure to fill in */
{
int i;
statusInfoPtr->processor = pcbPtr->processor;
statusInfoPtr->state = pcbPtr->state;
statusInfoPtr->genFlags = pcbPtr->genFlags;
statusInfoPtr->processID = pcbPtr->processID;
statusInfoPtr->parentID = pcbPtr->parentID;
statusInfoPtr->familyID = pcbPtr->familyID;
statusInfoPtr->userID = pcbPtr->userID;
statusInfoPtr->effectiveUserID = pcbPtr->effectiveUserID;
statusInfoPtr->event = pcbPtr->event;
statusInfoPtr->billingRate = pcbPtr->billingRate;
statusInfoPtr->recentUsage = pcbPtr->recentUsage;
statusInfoPtr->weightedUsage = pcbPtr->weightedUsage;
statusInfoPtr->unweightedUsage = pcbPtr->unweightedUsage;
statusInfoPtr->kernelCpuUsage = pcbPtr->kernelCpuUsage.time;
statusInfoPtr->userCpuUsage = pcbPtr->userCpuUsage.time;
statusInfoPtr->childKernelCpuUsage = pcbPtr->childKernelCpuUsage.time;
statusInfoPtr->childUserCpuUsage = pcbPtr->childUserCpuUsage.time;
statusInfoPtr->numQuantumEnds = pcbPtr->numQuantumEnds;
statusInfoPtr->numWaitEvents = pcbPtr->numWaitEvents;
statusInfoPtr->schedQuantumTicks = pcbPtr->schedQuantumTicks;
for(i = 0; i < VM_NUM_SEGMENTS; i++) {
if (pcbPtr->vmPtr != (Vm_ProcInfo *) NIL &&
pcbPtr->vmPtr->segPtrArray[i] != (Vm_Segment *) NIL) {
statusInfoPtr->vmSegments[i] =
(Vm_SegmentID) pcbPtr->vmPtr->segPtrArray[i]->segNum;
} else {
statusInfoPtr->vmSegments[i] = (Vm_SegmentID) -1;
}
}
statusInfoPtr->sigHoldMask = pcbPtr->sigHoldMask;
statusInfoPtr->sigPendingMask = pcbPtr->sigPendingMask;
for(i = 0; i < SIG_NUM_SIGNALS; i++) {
statusInfoPtr->sigActions[i] = pcbPtr->sigActions[i];
}
statusInfoPtr->peerHostID = pcbPtr->peerHostID;
statusInfoPtr->peerProcessID = pcbPtr->peerProcessID;
}
/*
*----------------------------------------------------------------------
*
* Proc_RpcGetPCB --
*
* Stub to handle a remote request for a PCB or Vm_Segment.
*
* Results:
* Status of reply:
* GEN_INVALID_ARG - index into table of process control blocks is
* invalid, or segment is invalid.
* SUCCESS - information is returned.
*
* SUCCESS is passed to the caller on this machine.
*
* Side effects:
* Reply is sent.
*
*----------------------------------------------------------------------
*/
/*ARGSUSED*/
ReturnStatus
Proc_RpcGetPCB(srvToken, clientID, command, storagePtr)
ClientData srvToken; /* Handle on server process passed to
* Rpc_Reply */
int clientID; /* Sprite ID of client host */
int command; /* Command identifier */
register Rpc_Storage *storagePtr; /* The request fields refer to the
* request buffers and also indicate
* the exact amount of data in the
* request buffers. The reply fields
* are initialized to NIL for the
* pointers and 0 for the lengths.
* This can be passed to Rpc_Reply */
{
ReturnStatus status = SUCCESS;
Proc_PID *pidPtr;
Rpc_ReplyMem *replyMemPtr;
Proc_PCBInfo *pcbPtr;
Proc_ControlBlock *procPtr = (Proc_ControlBlock *) NIL;
Proc_ControlBlock pcb;
int *segNumPtr;
Vm_SegmentInfo *segInfoPtr;
int *requestPtr;
requestPtr = (int *) storagePtr->requestParamPtr;
if (*requestPtr == GET_SEG_INFO) {
segNumPtr = (int *) storagePtr->requestDataPtr;
segInfoPtr = (Vm_SegmentInfo *) malloc(sizeof (Vm_SegmentInfo));
status = Vm_EncapSegInfo(*segNumPtr, segInfoPtr);
storagePtr->replyParamPtr = (Address) segInfoPtr;
storagePtr->replyParamSize = sizeof(Vm_SegmentInfo);
goto done;
} else if (*requestPtr == GET_PCB) {
pidPtr = (Proc_PID *) storagePtr->requestDataPtr;
if (*pidPtr >= proc_MaxNumProcesses) {
status = GEN_INVALID_ARG;
} else {
procPtr = Proc_GetPCB(*pidPtr);
if (procPtr == (Proc_ControlBlock *) NIL) {
panic("Proc_RpcGetPCB: found nil PCB!");
status = FAILURE;
}
}
if (status != SUCCESS) {
Rpc_Reply(srvToken, status, storagePtr,
(int(*)())NIL, (ClientData)NIL);
return(SUCCESS);
}
bcopy((Address) procPtr, (Address) &pcb, sizeof (Proc_ControlBlock));
TICKS_TO_TIME(pcb);
pcbPtr = (Proc_PCBInfo *) malloc(sizeof (Proc_PCBInfo));
storagePtr->replyParamPtr = (Address) pcbPtr;
storagePtr->replyParamSize = sizeof(Proc_PCBInfo);
FillPCBInfo(&pcb, pcbPtr);
if (procPtr->argString != (Address) NIL) {
storagePtr->replyDataSize = strlen(procPtr->argString) + 1;
storagePtr->replyDataPtr = (Address) malloc(storagePtr->replyDataSize);
(void) strcpy(storagePtr->replyDataPtr, procPtr->argString);
} else {
storagePtr->replyDataSize = 0;
storagePtr->replyDataPtr = (Address) NIL;
}
}
done:
replyMemPtr = (Rpc_ReplyMem *) malloc(sizeof(Rpc_ReplyMem));
replyMemPtr->paramPtr = storagePtr->replyParamPtr;
replyMemPtr->dataPtr = storagePtr->replyDataPtr;
Rpc_Reply(srvToken, status, storagePtr, Rpc_FreeMem,
(ClientData) replyMemPtr);
return(SUCCESS);
}
/*
*----------------------------------------------------------------------
*
* Proc_GetResUsage --
*
* Returns the resource usage for a process.
*
* Results:
* SYS_INVALID_ARG - buffer address was invalid.
* PROC_INVALID_PID - The pid was out-of-range or specified a
* non-existent process.
* SYS_ARG_NOACCESS - The buffers to store the pcbs in were not
* accessible.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
ReturnStatus
Proc_GetResUsage(pid, bufferPtr)
Proc_PID pid;
Proc_ResUsage *bufferPtr;
{
register Proc_ControlBlock *procPtr;
Proc_ResUsage resUsage;
ReturnStatus status = SUCCESS;
if (pid == PROC_MY_PID) {
procPtr = Proc_GetEffectiveProc();
if (procPtr == (Proc_ControlBlock *) NIL) {
panic("Proc_GetResUsage: procPtr == NIL\n");
}
Proc_Lock(procPtr);
} else {
procPtr = Proc_LockPID(pid);
if (procPtr == (Proc_ControlBlock *) NIL) {
return (PROC_INVALID_PID);
}
}
/*
* Copy the information to the out parameters.
*/
if (bufferPtr == USER_NIL) {
status = SYS_INVALID_ARG;
} else {
Timer_TicksToTime(procPtr->kernelCpuUsage.ticks,
&resUsage.kernelCpuUsage);
Timer_TicksToTime(procPtr->userCpuUsage.ticks, &resUsage.userCpuUsage);
Timer_TicksToTime(procPtr->childKernelCpuUsage.ticks,
&resUsage.childKernelCpuUsage);
Timer_TicksToTime(procPtr->childUserCpuUsage.ticks,
&resUsage.childUserCpuUsage);
resUsage.numQuantumEnds = procPtr->numQuantumEnds;
resUsage.numWaitEvents = procPtr->numWaitEvents;
if (Proc_ByteCopy(FALSE, sizeof(Proc_ResUsage),
(Address) &resUsage, (Address) bufferPtr) != SUCCESS){
status = SYS_ARG_NOACCESS;
}
}
Proc_Unlock(procPtr);
return(status);
}
/*
*----------------------------------------------------------------------
*
* Proc_GetPriority --
*
* Returns the priority of a process.
*
* Results:
* SYS_INVALID_ARG - priorityPtr address was invalid.
* PROC_INVALID_PID - The pid was out-of-range or specified a
* non-existent process.
* SYS_ARG_NOACCESS - The buffer to store the priority was not
* accessible.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
ReturnStatus
Proc_GetPriority(pid, priorityPtr)
Proc_PID pid; /* ID of process whose priority is to be returned. */
int *priorityPtr; /* Priority returned by Proc_GetPriority. */
{
register Proc_ControlBlock *procPtr;
ReturnStatus status = SUCCESS;
if (pid == PROC_MY_PID) {
procPtr = Proc_GetEffectiveProc();
if (procPtr == (Proc_ControlBlock *) NIL) {
panic("Proc_GetPriority: procPtr == NIL\n");
}
Proc_Lock(procPtr);
} else {
procPtr = Proc_LockPID(pid);
if (procPtr == (Proc_ControlBlock *) NIL) {
return (PROC_INVALID_PID);
}
}
/*
* Copy the information to the out parameter.
*/
if (priorityPtr == USER_NIL) {
status = SYS_INVALID_ARG;
} else {
if (Proc_ByteCopy(FALSE, sizeof(int),
(Address) &(procPtr->billingRate),
(Address) priorityPtr) != SUCCESS) {
status = SYS_ARG_NOACCESS;
}
}
Proc_Unlock(procPtr);
return(status);
}
/*
*----------------------------------------------------------------------
*
* Proc_SetPriority --
*
* Sets the priority for a process.
*
* Results:
* PROC_INVALID_PID - The pid was out-of-range or specified a
* non-existent process.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
ReturnStatus
Proc_SetPriority(pid, priority, useFamily)
Proc_PID pid; /* ID of process whose priority is to be set. */
int priority; /* New scheduling priority for pid. */
Boolean useFamily; /* If TRUE, use pid as the head of a process
* family, and set the priority of every
* process in the family. */
{
register Proc_ControlBlock *procPtr;
register Proc_PCBLink *procLinkPtr;
List_Links *familyList;
int userID;
ReturnStatus status;
if (priority > PROC_MAX_PRIORITY) {
priority = PROC_MAX_PRIORITY;
} else if (priority < PROC_MIN_PRIORITY) {
priority = PROC_MIN_PRIORITY;
}
if (useFamily) {
/*
* Set priorities of processes in family.
*/
status = Proc_LockFamily((int) pid, &familyList, &userID);
if (status != SUCCESS) {
return(status);
}
if (!Proc_HasPermission(userID)) {
Proc_UnlockFamily((int) pid);
return(PROC_UID_MISMATCH);
}
LIST_FORALL(familyList, (List_Links *) procLinkPtr) {
procPtr = procLinkPtr->procPtr;
Proc_Lock(procPtr);
procPtr->billingRate = priority;
Proc_Unlock(procPtr);
}
Proc_UnlockFamily((int) pid);
} else {
/*
* Set the individual process's priority.
*/
if (pid == PROC_MY_PID) {
procPtr = Proc_GetEffectiveProc();
Proc_Lock(procPtr);
} else {
procPtr = Proc_LockPID(pid);
if (procPtr == (Proc_ControlBlock *) NIL) {
return (PROC_INVALID_PID);
}
if (!Proc_HasPermission(procPtr->effectiveUserID)) {
Proc_Unlock(procPtr);
return(PROC_UID_MISMATCH);
}
}
procPtr->billingRate = priority;
Proc_Unlock(procPtr);
}
return(SUCCESS);
}
/*
*----------------------------------------------------------------------
*
* Proc_Profile --
*
* Starts profiling the memory accesses of the current process.
*
* Results:
* SUCCESS - always returned for now.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
/*ARGSUSED*/
ReturnStatus
Proc_Profile(shiftSize, lowPC, highPC, interval, counterArray)
int shiftSize; /* # of bits to shift the PC to the right. */
int lowPC; /* The lowest PC to profile. */
int highPC; /* The highest PC to profile. */
Time interval; /* The time interval at which the PC is sampled. */
int counterArray[]; /* Counters used to count instruction executions. */
{
return(SUCCESS);
}
/*
*----------------------------------------------------------------------
*
* Proc_Dump --
*
* Prints out an abbreviated proc table for debugging purposes.
*
* Results:
* SUCCESS.
*
* Side effects:
* Prints stuff to screen.
*
*
*----------------------------------------------------------------------
*/
ReturnStatus
Proc_Dump()
{
int i;
Proc_ControlBlock *pcbPtr;
printf("\n%8s %5s %10s %10s %8s %8s %s\n",
"ID", "wtd", "user", "kernel", "event", "state", "name");
for (i = 0; i < proc_MaxNumProcesses; i++) {
pcbPtr = proc_PCBTable[i];
if (pcbPtr->state != PROC_UNUSED) {
Proc_DumpPCB(pcbPtr);
}
}
return(SUCCESS);
}
/*
*----------------------------------------------------------------------
*
* Proc_DumpPCB --
*
* Prints out the contents of a PCB for debugging purposes.
*
* Results:
* None.
*
* Side effects:
* Prints stuff to the screen.
*
*----------------------------------------------------------------------
*/
void
Proc_DumpPCB(procPtr)
Proc_ControlBlock *procPtr;
{
Time kernelTime, userTime;
#define DEBUG_INDEX 0x9
static char *states[] = {
"unused",
"running",
"ready",
"waiting",
"exiting",
"dead",
"migrated",
"new",
"suspended",
"debug",
};
Proc_State state;
state = procPtr->state;
switch (state) {
case PROC_UNUSED:
case PROC_RUNNING:
case PROC_READY:
case PROC_WAITING:
case PROC_EXITING:
case PROC_DEAD:
case PROC_MIGRATED:
case PROC_NEW:
break;
case PROC_SUSPENDED:
/* If process is suspended for debugging print "debug" for its
* state.
*/
if (procPtr->genFlags & (PROC_DEBUGGED | PROC_ON_DEBUG_LIST)) {
state = (Proc_State)DEBUG_INDEX;
}
break;
default:
printf("Warning: Proc_DumpPCB: process %x has invalid process state: %x.\n",
procPtr->processID, state);
return;
}
/*
* A header describing the fields has already been printed.
*/
Timer_TicksToTime(procPtr->userCpuUsage.ticks, &userTime);
Timer_TicksToTime(procPtr->kernelCpuUsage.ticks, &kernelTime);
printf("%8x %5d [%1d,%6d] [%1d,%6d] %8x %8s",
procPtr->processID,
procPtr->weightedUsage,
userTime.seconds,
userTime.microseconds,
kernelTime.seconds,
kernelTime.microseconds,
procPtr->event,
states[(int) state]);
if (procPtr->argString != (Address) NIL) {
char cmd[30];
char *space;
(void) strncpy(cmd, procPtr->argString, 30);
space = strchr(cmd, ' ');
if (space != (char *) NULL) {
*space = '\0';
}
printf(" %s\n", cmd);
} else {
printf("\n");
}
}
/*
*----------------------------------------------------------------------
*
* Proc_KillAllProcesses --
*
* Send the kill signal to all processes in the proc table except for
* the caller. If userProcsOnly is TRUE only send signals to user
* processes.
*
* Results:
* The number of runnable and waiting processes.
*
* Side effects:
* The kill signal bit is set for all processes.
*
*----------------------------------------------------------------------
*/
int
Proc_KillAllProcesses(userProcsOnly)
Boolean userProcsOnly; /* TRUE if only kill user processes. */
{
register int i;
register Proc_ControlBlock *pcbPtr;
Proc_ControlBlock *curProcPtr;
int alive = 0;
curProcPtr = Proc_GetActualProc();
for (i = 0; i < proc_MaxNumProcesses; i++) {
pcbPtr = proc_PCBTable[i];
if (pcbPtr == curProcPtr || pcbPtr->state == PROC_UNUSED ||
(userProcsOnly && !(pcbPtr->genFlags & PROC_USER))) {
continue;
}
Proc_Lock(pcbPtr);
if (pcbPtr->state == PROC_RUNNING ||
pcbPtr->state == PROC_READY ||
pcbPtr->state == PROC_WAITING ||
pcbPtr->state == PROC_MIGRATED) {
alive++;
(void) Sig_SendProc(pcbPtr, SIG_KILL, 0, (Address)0);
}
Proc_Unlock(pcbPtr);
}
return(alive);
}
/*
*----------------------------------------------------------------------
*
* Proc_WakeupAllProcesses --
*
* Wakup all waiting processes.
*
* Results:
* None.
*
* Side effects:
* All waiting processes are awakened.
*
*----------------------------------------------------------------------
*/
void
Proc_WakeupAllProcesses()
{
register int i;
register Proc_ControlBlock *pcbPtr;
Proc_ControlBlock *curProcPtr;
curProcPtr = Proc_GetActualProc();
for (i = 0; i < proc_MaxNumProcesses; i++) {
pcbPtr = proc_PCBTable[i];
if (pcbPtr == curProcPtr) {
continue;
}
Proc_Lock(pcbPtr);
if (pcbPtr->state != PROC_UNUSED) {
Sync_WakeWaitingProcess(pcbPtr);
}
Proc_Unlock(pcbPtr);
}
}
/*
*----------------------------------------------------------------------
*
* Proc_HasPermission --
*
* See if the current process has permission to perform an operation on
* a process with the given user id.
*
* Results:
* TRUE if the current process has the same effective user id
* as the given user id or the current process is super user.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
Boolean
Proc_HasPermission(userID)
int userID;
{
Proc_ControlBlock *procPtr;
procPtr = Proc_GetEffectiveProc();
return(procPtr->effectiveUserID == userID ||
procPtr->effectiveUserID == PROC_SUPER_USER_ID);
}
/*
*----------------------------------------------------------------------
*
* Proc_DoForEveryProc --
*
* For every process in the process table, apply *booleanFuncPtr to it.
* If that returns TRUE, apply *actionFuncPtr to it. This is done by
* passing booleanFuncPtr to a monitored routine and having it
* return an array of qualifying processes. There is a bit of a race
* condition if something happens to any of those processes after the
* list is returned, but in that case the process is ignored and the next
* one is processed.
*
* IgnoreStatus indicates whether the routine should abort if
* a non-SUCCESS status is returned by *actionFuncPtr.
*
* Results:
* If anything "unexpected" happens, FAILURE will be returned, but in
* general SUCCESS is returned. If numMatchedPtr is non-NIL, then
* the number of processes matched is returned in *numMatchedPtr.
*
* Side effects:
* The process table is locked temporarily. Otherwise, dependent on the
* call-back procedures.
*
*----------------------------------------------------------------------
*/
ReturnStatus
Proc_DoForEveryProc(booleanFuncPtr, actionFuncPtr, ignoreStatus, numMatchedPtr)
Boolean (*booleanFuncPtr) _ARGS_((Proc_ControlBlock *pcbPtr));
/* function to match */
ReturnStatus (*actionFuncPtr)_ARGS_((Proc_PID pid));
/* function to invoke on matches */
Boolean ignoreStatus; /* do not abort if bad ReturnStatus */
int *numMatchedPtr; /* number of matches in table, or NIL */
{
ReturnStatus status = SUCCESS;
Proc_PID *pidArray;
int max;
int i;
int numMatched;
max = proc_MaxNumProcesses;
pidArray = (Proc_PID *) malloc(sizeof(Proc_PID) * max);
numMatched = ProcTableMatch(max, booleanFuncPtr, pidArray);
for (i = 0; i < numMatched; i++) {
status = (*actionFuncPtr)(pidArray[i]);
if ((!ignoreStatus) && (status != SUCCESS)) {
break;
}
}
free((Address) pidArray);
if (numMatchedPtr != (int *) NIL) {
*numMatchedPtr = numMatched;
}
if (ignoreStatus) {
return(SUCCESS);
}
return(status);
}
/*
*----------------------------------------------------------------------
*
* Proc_SetServerPriority --
*
* Changes the priority of a server process to the non-interruptable
* value. The pid is assumed to be valid.
*
* Results:
* None.
*
* Side effects:
* The process's priority is changed.
*
*----------------------------------------------------------------------
*/
void
Proc_SetServerPriority(pid)
Proc_PID pid;
{
Proc_GetPCB(pid)->billingRate = PROC_NO_INTR_PRIORITY;
}
/*
*----------------------------------------------------------------------
*
* Proc_GetHostIDs --
*
* Returns the sprite IDs corresponding to the machines on which
* the current process is effectively executing and on which
* it is physically executing. These hosts are called the virtualHost
* and physicalHost, respectively. For an unmigrated process, these
* two are identical.
*
* Results:
* SUCCESS The call was successful.
* SYS_ARG_NOACCESS The user arguments were not accessible.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
ReturnStatus
Proc_GetHostIDs(virtualHostPtr, physicalHostPtr)
int *virtualHostPtr; /* Buffer to hold virtual host ID. */
int *physicalHostPtr; /* Buffer to hold physical host ID. */
{
Proc_ControlBlock *procPtr;
int host;
if (physicalHostPtr != (int *) USER_NIL) {
if (Vm_CopyOut(sizeof(int), (Address) &rpc_SpriteID,
(Address) physicalHostPtr) != SUCCESS) {
return(SYS_ARG_NOACCESS);
}
}
if (virtualHostPtr != (int *) USER_NIL) {
procPtr = Proc_GetCurrentProc();
Proc_Lock(procPtr);
host = procPtr->peerHostID;
Proc_Unlock(procPtr);
if (host == NIL) {
host = rpc_SpriteID;
}
if (Vm_CopyOut(sizeof(int), (Address) &host,
(Address) virtualHostPtr) != SUCCESS) {
return(SYS_ARG_NOACCESS);
}
}
return(SUCCESS);
}
/*
*----------------------------------------------------------------------
*
* Proc_PushLockStack --
*
* Pushes the given lock type on the lock stack for the process.
*
* Results:
* None.
*
* Side effects:
* Stuff is printed if the stack overflows.
*
*----------------------------------------------------------------------
*/
/*ARGSUSED*/
void
Proc_PushLockStack(pcbPtr, type, lockPtr)
Proc_ControlBlock *pcbPtr; /* ptr to pcb to modify */
int type; /* type of lock */
Address lockPtr; /* ptr to lock */
{
#ifdef LOCKDEP
static Boolean firstOverflow = TRUE;
/*
* Modifying the lock stack of a process has to be an atomic operation,
* but we don't want to use a lock to do this, since this is part of
* the code used when locking or unlocking. Using a lock would lead
* to a circularity and probably a deadlock. All we really need to
* prevent is an interrupt handler from grabbing a lock while we're
* modifying the lock stack. A process only modifies its own
* lock stack, so turning off interrupts should be good enough.
*/
DISABLE_INTR();
if (pcbPtr->lockStackSize >= PROC_LOCKSTACK_SIZE) {
if (firstOverflow) {
printf("Proc_PushLockStack: stack overflow in pcb 0x%x.\n",pcbPtr);
firstOverflow = FALSE;
}
goto exit;
}
if (pcbPtr->lockStackSize < 0 ) {
printf("Proc_PushLockStack: stack underflow (%d) in pcb 0x%x.\n",
pcbPtr->lockStackSize, pcbPtr);
goto exit;
}
pcbPtr->lockStack[pcbPtr->lockStackSize].type = type;
pcbPtr->lockStack[pcbPtr->lockStackSize].lockPtr = lockPtr;
pcbPtr->lockStackSize++;
exit:
ENABLE_INTR();
#endif
}
/*
*----------------------------------------------------------------------
*
* Proc_RemoveFromLockStack --
*
* Removes the given lock from the stack if it is there.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
/*ARGSUSED*/
void
Proc_RemoveFromLockStack(pcbPtr, lockPtr)
Proc_ControlBlock *pcbPtr; /* ptr to pcb to modify */
Address lockPtr; /* ptr to lock */
{
#ifdef LOCKDEP
int i;
int stackTop;
Boolean found = FALSE;
DISABLE_INTR();
if (pcbPtr->lockStackSize < 0) {
ENABLE_INTR();
panic("Lock stack underflow (1).\n");
goto exit;
}
if (pcbPtr->lockStackSize == 0) {
goto exit;
}
stackTop = pcbPtr->lockStackSize - 1;
for (i = pcbPtr->lockStackSize - 1; i >= 0; i--) {
if (pcbPtr->lockStack[i].lockPtr == lockPtr) {
pcbPtr->lockStack[i].lockPtr = (Address) NIL;
pcbPtr->lockStack[i].type = -1;
found = TRUE;
break;
}
}
if (!found) {
goto exit;
}
for (i = stackTop; i >= 0; i--) {
if (pcbPtr->lockStack[i].lockPtr != (Address) NIL) {
break;
}
}
pcbPtr->lockStackSize = i + 1;
if (pcbPtr->lockStackSize < 0) {
printf("lockStackSize %d\n",pcbPtr->lockStackSize);
}
exit:
ENABLE_INTR();
#endif
}
#ifndef LOCKREG
#ifndef CLEAN_LOCK
#ifndef CLEAN
/*
*----------------------------------------------------------------------
*
* Proc_KDump --
*
* Prints out an (kluged) proc table with state information.
*
* This routine uses several macros to analyse the event data structure:
* ISADDR(x) tests if x is a valid address.
* ISSTR(x) tests if x is a pointer to a valid string.
* ISALIGN(x) tests if x is an aligned address.
* ISBOOL(x) tests if x is a boolean.
* ISSMALL(x) tests is x is a small integer.
* ISLIST(x) tests if x points to a List_Links structure.
* ISPCB(x) tests if x points to a Proc_ControlBlock structure.
* ISHANDLE(x) tests is x points to a Fs_HandleHeader structure.
* FIELD(x,type,field) is x->type.field
*
* Results:
* SUCCESS.
*
* Side effects:
* Prints stuff to screen.
*
*
*----------------------------------------------------------------------
*/
#define INT(x) ((int)(x))
#define INTP(x) ((int *)(x))
#define ISADDRR(x,range) ((INT(x)&1)==0 && Dbg_InRange((unsigned)(x),2,FALSE)\
&& Dbg_InRange(((unsigned)(x))+(range)-2,2,FALSE))
#define ISADDR(x) ISADDRR(x,sizeof(int))
#define ISSTR(x) (ISADDRR(x,20) && \
(strncpy(buf,(char *)(x),20),strlen(buf)<20) && isprint(buf[0]))
#define ISSTRZ(x) (INT(x)==0 || ISSTR(x))
#define ISALIGN(x) (ISADDR(x) && (INT(x)&3)==0)
#define ISALIGNZ(x) (INT(x)==0 || ISALIGN(x))
/* sun3 test-and-set sets to 0x80000000, sun4 to 0xff000000 */
#define ISBOOL(x) (INT(x)==0||INT(x)==1||INT(x)==0x80000000||\
INT(x)==0xff000000)
#define ISSMALL(x) (INT(x)>=0&&INT(x)<20)
#define ISPCBZ(x) (INT(x)==0||ISPCB(x))
#define OFF(type,field) (INTP(&(((type *)0)->field))-INTP(0))
#define FIELD(var,type,field) (((type *)(var))->field)
#define P_cb Proc_ControlBlock
#define Fc_b Fscache_Block
#define Fc_fi Fscache_FileInfo
#define F_hh Fs_HandleHeader
#define L_L List_Links
#define HANDLENAME(x) (Fsutil_HandleName((Fs_HandleHeader *)(x)))
#define PRINTHANDLE(str,handle) printf("%s: \"%s\" (handle locked by %x)",\
str, HANDLENAME(handle), handle->lockProcPtr)
char buf[21] = {0};
static int ISLIST(x)
List_Links *x;
{
return ISADDRR(x,sizeof(List_Links)) && ISADDR(x->prevPtr) &&
ISADDR(x->nextPtr);
}
static int ISPCB(x)
Proc_ControlBlock *x;
{
return ISADDRR(x,sizeof(Proc_ControlBlock)) && ISLIST(&x->links) &&
ISSMALL(x->processor) && ISLIST(&x->childListHdr) &&
x->processID <= 0xfffff;
}
static int ISHANDLE(x)
Fs_HandleHeader *x;
{
return ISADDRR(x,sizeof(Fs_HandleHeader)) && ISLIST(&x->lruLinks) &&
ISBOOL(x->unlocked.waiting) && ISSMALL(x->refCount) &&
ISSTRZ(x->name) &&
(x->lockProcPtr == (Proc_ControlBlock *)NIL
|| ISPCB(x->lockProcPtr));
}
static int ISRPCCLIENT(x)
RpcClientChannel *x;
{
int i;
if (!ISADDRR(x,sizeof(RpcClientChannel))) return 0;
for (i=0;i<rpcNumChannels;i++) {
if (rpcChannelPtrPtr[i] == x) return 1;
}
return 0;
}
static int ISRPCSERVER(x)
RpcServerState *x;
{
int i;
if (!ISADDRR(x,sizeof(RpcServerState))) return 0;
for (i=0;i<rpcMaxServers;i++) {
if (rpcServerPtrPtr[i] == x) return 1;
}
return 0;
}
static int ISSERVERPROC(x)
ServerInfo *x;
{
int i;
if (!ISADDRR(x,sizeof(ServerInfo))) return 0;
for (i=0;i<proc_NumServers;i++) {
if (serverInfoTable+i == x) return 1;
}
return 0;
}
static int ISLOCK(x)
Sync_Lock *x;
{
return ISADDRR(x,sizeof(Sync_Lock)) && ISBOOL(x->inUse) &&
ISBOOL(x->waiting) && ISSTR(x->name) && ISALIGNZ(x->holderPC) &&
ISPCBZ(x->holderPCBPtr);
}
static int ISSEM(x)
Sync_Semaphore *x;
{
return ISADDRR(x,sizeof(Sync_Semaphore)) && ISSMALL(x->value) &&
ISSTR(x->name) && ISALIGNZ(x->holderPC) && ISPCBZ(x->holderPCBPtr);
}
typedef struct LockEntry {
int addr; /* Address (event) associated with the lock. */
char *name; /* Name of the lock event. */
} LockEntry;
extern Sync_Condition cleanBlockCondition, writeBackComplete,
closeCondition, lruDone, debugListCondition, familyCondition,
migrateCondition, evictCondition, recovCondition, recovPingCondition,
rpcDaemon, freeChannels, signalCondition, codeSegCondition,
cleanCondition, swapDownCondition, mappingCondition, swapFileCondition;
LockEntry locks[] = {
(int)&cleanBlockCondition, "cleanBlockCondition",
(int)&writeBackComplete, "writeBackComplete",
(int)&closeCondition, "closeCondition",
(int)&lruDone, "lruDone",
(int)&debugListCondition, "debugListCondition",
(int)&familyCondition, "familyCondition",
(int)&migrateCondition, "migrateCondition",
(int)&evictCondition, "evictCondition",
(int)&recovCondition, "recovCondition",
(int)&rpcDaemon, "rpcDaemon",
(int)&freeChannels, "freeChannels",
(int)&signalCondition, "signalCondition",
(int)&codeSegCondition, "codeSegCondition",
(int)&cleanCondition, "cleanCondition",
(int)&swapDownCondition, "swapDownCondition",
(int)&mappingCondition, "mappingCondition",
(int)&swapFileCondition, "swapFileCondition",
(int)&recovPingCondition, "recovPingCondition",
0, 0
};
/*ARGSUSED*/
void
Proc_KDump(dummy)
ClientData dummy; /* unused - see dump.c:eventTable */
{
int i;
Proc_ControlBlock *procPtr, *tmpProcPtr;
int *event;
LockEntry *lockPtr;
Fscache_FileInfo *cacheInfoPtr;
Fs_HandleHeader *handlePtr;
RpcClientChannel *rpcClientPtr;
RpcServerState *rpcServerPtr;
ServerInfo *serverProcPtr;
int match;
for (i = 0; i < proc_MaxNumProcesses; i++) {
procPtr = proc_PCBTable[i];
match = 0;
if (procPtr->state == PROC_WAITING) {
printf("%8x", procPtr->processID);
if (procPtr->argString != (Address) NIL) {
char cmd[30];
char *space;
(void) strncpy(cmd, procPtr->argString, 30);
space = strchr(cmd, ' ');
if (space != (char *) NULL) {
*space = '\0';
} else {
cmd[29] = '\0';
}
printf("(%s)", cmd);
}
printf(": waiting on ");
event = (int *)procPtr->event;
if (ISADDR(event)) {
for (lockPtr = locks ; lockPtr->addr != 0; lockPtr++) {
if ((int)event == lockPtr->addr) {
printf("condition \"%s\"\n", lockPtr->name);
goto found;
}
}
if (ISLOCK((Sync_Lock *)event)) {
/* Sync_Lock / Sync_KernelLock */
printf("lock \"%s\" at %x", (char *)(event[2]),
(int)event[3]);
if (ISPCB((P_cb *)event[4])) {
printf(" held by process %x",
((Proc_ControlBlock *)(event[4]))->processID);
}
} else if (ISPCB((P_cb *)event)) {
/* Proc_ControlBlock */
printf("timer %x",
((Proc_ControlBlock *)event)->processID);
} else if (ISSEM((Sync_Semaphore *)event)) {
/* Sync_Semaphore */
printf("semaphore \"%s\" at %x",
(char *)(event[1]), (int)(event[2]));
if (ISPCB((P_cb *)event[3])) {
printf(" held by process %x",
((Proc_ControlBlock *)(event[3]))->processID);
}
} else if (ISBOOL(event[0])) {
/* Sync_Condition */
handlePtr = (F_hh *)(event-OFF(F_hh,unlocked));
if (ISHANDLE(handlePtr)) {
PRINTHANDLE("handle: \"unlocked\"", handlePtr);
match++;
}
handlePtr = (F_hh *)(FIELD(event-OFF(Fc_fi,noDirtyBlocks),
Fc_fi, hdrPtr));
if (ISHANDLE(handlePtr)) {
PRINTHANDLE("cache block: \"noDirtyBlocks\"",
handlePtr);
match++;
}
/* See if intPtr is a cacheInfoPtr */
cacheInfoPtr = (Fc_fi *)FIELD(event-OFF(Fc_b,ioDone), Fc_b,
cacheInfoPtr);
if (ISADDRR(cacheInfoPtr,sizeof(Fc_fi)) &&
ISHANDLE(cacheInfoPtr->hdrPtr)) {
PRINTHANDLE("cache block: \"ioDone\"",
cacheInfoPtr->hdrPtr);
match++;
}
tmpProcPtr = (P_cb *)(event-OFF(P_cb,waitCondition));
if (ISPCB(tmpProcPtr)) {
printf("PCB: \"waitCondition\" ");
match++;
}
tmpProcPtr = (P_cb *)(event-OFF(P_cb,lockedCondition));
if (ISPCB(tmpProcPtr)) {
printf("PCB: \"lockedCondition\" ");
match++;
}
serverProcPtr = (ServerInfo *)(event-
OFF(ServerInfo, condition));
if (ISSERVERPROC(serverProcPtr)) {
printf("ServerProc: \"condition\" ");
if (serverProcPtr->flags & ENTRY_INUSE) {
printf("INUSE ");
}
if (serverProcPtr->flags & SERVER_BUSY) {
printf("BUSY ");
}
if (serverProcPtr->flags & FUNC_PENDING) {
printf("PENDING ");
}
match++;
}
rpcClientPtr = (RpcClientChannel *)(event-
OFF(RpcClientChannel, waitCondition));
if (ISRPCCLIENT(rpcClientPtr)) {
printf("RPC client: \"waitCondition\", server %d ",
rpcClientPtr->serverID);
if (rpcClientPtr->state & CHAN_FREE) printf("FREE ");
if (rpcClientPtr->state & CHAN_BUSY) printf("BUSY ");
if (rpcClientPtr->state & CHAN_WAITING) printf("WAIT ");
if (rpcClientPtr->state & CHAN_TIMEOUT) printf("TIME ");
if (rpcClientPtr->state & CHAN_FRAGMENTING) {
printf("FRAG ");
}
match++;
}
rpcServerPtr = (RpcServerState *)(event-
OFF(RpcServerState, waitCondition));
if (ISRPCSERVER(rpcServerPtr)) {
printf("RPC server:\"waitCondition\", client %d ",
rpcServerPtr->clientID);
if (rpcServerPtr->state & SRV_NOTREADY) {
printf("NOTREADY ");
}
if (rpcServerPtr->state & SRV_FREE) printf("FREE ");
if (rpcServerPtr->state & SRV_BUSY) printf("BUSY ");
if (rpcServerPtr->state & SRV_WAITING) printf("WAIT ");
if (rpcServerPtr->state & SRV_AGING) printf("AGING ");
if (rpcServerPtr->state & SRV_FRAGMENT) printf("FRAG ");
if (rpcServerPtr->state & SRV_NO_REPLY) {
printf("NO_REPLY ");
}
if (rpcServerPtr->state & SRV_STUCK) printf("STUCK ");
match++;
}
handlePtr = (F_hh *)(event-OFF(Fsrmt_IOHandle,
recovery.reopenComplete));
if (ISHANDLE(handlePtr)) {
PRINTHANDLE("\"recovery.reopenComplete\"", handlePtr);
match++;
}
if (!match) {
printf("condition %x", (int)event);
} else if (match>1) {
printf("(Ambiguous)");
}
} else {
printf("event %x", (int)event);
}
} else if ((int)event == -1) {
printf("wakeup signal");
} else {
printf("event? %x", (int)event);
}
printf("\n");
found:;
}
}
}
#define KDUMP
#endif
#endif
#endif
#ifndef KDUMP
/* ARGSUSED */
ReturnStatus
Proc_KDump(dummy)
ClientData dummy;
{
return SUCCESS;
}
#endif